﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Globalization;
using System.Drawing.Drawing2D;
using Toolkit;

namespace CustomControls {
  /// <summary>
  /// Nullable DateTimePicker control
  /// </summary>
  [ToolboxBitmap( typeof( NullDateTimePicker ), "NullDTP.bmp" ), DefaultBindingProperty( "Value" )]
  public partial class NullDateTimePicker : UserControl, INotifyPropertyChanged {

    /// <summary>
    /// DateFormatType
    /// </summary>
    public enum DateFormatType {
      Long,
      Short,
      Time,
      Custom
    }

    private DateFormatType dateFormat;
    private string customFormat;
    private DateTime? valueDate;

    #region - Properties -
    
    /// <summary>
    /// Gets or sets the date format.
    /// </summary>
    /// <value>
    /// The date format.
    /// </value>
    public DateFormatType DateFormat {
      get { return dateFormat; }
      set { dateFormat = value; }
    }

    /// <summary>
    /// Gets or sets the custom format.
    /// </summary>
    /// <value>
    /// The custom format.
    /// </value>
    public string CustomFormat {
      get { return customFormat; }
      set { customFormat = value; }
    }

    /// <summary>
    /// Gets or sets the value.
    /// </summary>
    /// <value>
    /// The value.
    /// </value>
    [Bindable( true )]
    public DateTime? Value {
      get { return this.valueDate; }
      set {
        this.valueDate = value;
        OnPropertyChanged( this, new PropertyChangedEventArgs( "Value" ) );

        if ( valueDate.HasValue ) {
          SetTextboxText( );
        } else {
          textBox.Text = string.Empty;
        }
      }
    }


    #endregion

    #region - Constructor -

    /// <summary>
    /// Initializes a new instance of the <see cref="NullDateTimePicker"/> class.
    /// </summary>
    public NullDateTimePicker( ) {
      InitializeComponent( );

      this.Size = new Size( 218, 21 );

      //textbox settings
      textBox.Location = new Point( 9, 3 );
      textBox.Size = new Size( 166, 13 );
      textBox.Anchor = AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Left;
      textBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
      textBox.TabStop = true;
      textBox.TabIndex = 0;
      textBox.CausesValidation = false;
      textBox.MouseDown += new MouseEventHandler( textBox_MouseDown );
      textBox.Leave += new EventHandler( textBox_Leave );

      //button settings
      button.Image = Properties.Resources.calendar_arrow;
      button.BackgroundImageLayout = ImageLayout.Stretch;
      button.Location = new Point( 180, 1 );
      button.Size = new Size( 37, 18 );
      button.Anchor = AnchorStyles.Top | AnchorStyles.Right;
      button.FlatAppearance.BorderSize = 0;
      button.FlatStyle = FlatStyle.Flat;
      button.UseVisualStyleBackColor = true;
      button.TabStop = false;
      button.CausesValidation = false;
      button.MouseDown += new MouseEventHandler( button_MouseDown );

      //Calender settings
      monthCalendar.Location = new Point( 0, 20 );
      monthCalendar.Size = new Size( 171, 162 );
      monthCalendar.TabStop = false;
      monthCalendar.MaxSelectionCount = 1;
      monthCalendar.Visible = false;
      monthCalendar.CausesValidation = false;
      monthCalendar.DateSelected += new DateRangeEventHandler( monthCalendar_DateSelected );
      monthCalendar.DateChanged += new DateRangeEventHandler( monthCalendar_DateChanged );
      monthCalendar.VisibleChanged += new EventHandler( monthCalendar_VisibleChanged );
      monthCalendar.Leave += new EventHandler( monthCalendar_Leave );
    }

    #endregion

    #region - Events -

    private void NullDateTimePicker_Load( object sender, EventArgs e ) {
      this.Refresh( );
      if ( this.Parent != null ) {
        this.Parent.Click += new EventHandler( Parent_Click );
      }
      Form form = this.FindForm( );
      if ( form != null ) {
        form.Click += new EventHandler( form_Click );
      }
    }

    void form_Click( object sender, EventArgs e ) {
      if ( monthCalendar.Visible ) {
        monthCalendar.Visible = false;
      }
    }

    void Parent_Click( object sender, EventArgs e ) {
      if ( monthCalendar.Visible ) {
        monthCalendar.Visible = false;
      }
    }

    private void NullDateTimePicker_Paint( object sender, PaintEventArgs e ) {

      //draw a rectangle round the textbox
      SolidBrush brush = new SolidBrush( Color.LightGray );
      Pen pen = new Pen( brush );
      GraphicTools.DrawRoundedRectangle( e.Graphics, pen, 0, 0, this.Width - 1, this.textBox.Height + 6, 2 );

      //draw a white rectangle behind the textbox (for filling)
      brush.Color = Color.White;
      e.Graphics.FillRectangle( brush, 1, 1, this.textBox.Width + textBox.Location.X + 4, textBox.Height + 5 );
    }

    void monthCalendar_DateChanged( object sender, DateRangeEventArgs e ) {
      this.Value = e.Start;
    }

    private void monthCalendar_DateSelected( object sender, DateRangeEventArgs e ) {
      this.Value = e.Start;
      if ( monthCalendar.Visible ) {
        monthCalendar.Visible = false;
      }

    }

    void monthCalendar_Leave( object sender, EventArgs e ) {
      if ( monthCalendar.Visible ) {

        monthCalendar.Visible = false;
      }
      textBox.Focus( );
    }

    private void monthCalendar_VisibleChanged( object sender, EventArgs e ) {
      if ( monthCalendar.Visible ) {
        monthCalendar.Select( );
      }
    }

    private void textBox_Leave( object sender, EventArgs e ) {

      try {
        DateTime date = DateTime.Parse( textBox.Text, CultureInfo.CurrentCulture );
        this.Value = date;
        SetTextboxText( );
        if ( monthCalendar.Visible ) {
          monthCalendar.Visible = false;
        }

      } catch ( ArgumentException ) {
        this.Value = null;
      } catch ( FormatException ) {
        this.Value = null;
      }

    }

    private void button_MouseDown( object sender, MouseEventArgs e ) {

      monthCalendar.Parent = this.ParentForm; //Toolstripcontrolhost
      Point controlScreenPoint = this.PointToScreen(new Point(0,this.Height-1) );
      Point formScreenPoint = this.ParentForm.PointToClient( controlScreenPoint );
      //Point p = this.ParentForm.PointToScreen( this.ParentForm.Location );
      //if ( this.ParentForm.Equals( this.Parent ) ) {
      //  monthCalendar.Location = new Point( this.Location.X, this.Location.Y + this.Height - 1 );
      //} else {
        monthCalendar.Location = formScreenPoint;
      //}

      monthCalendar.BringToFront( );

      monthCalendar.Visible = !monthCalendar.Visible;
      if ( !monthCalendar.Visible ) {
        textBox.Focus( );
      }
    }

    private void textBox_MouseDown( object sender, MouseEventArgs e ) {

      if ( monthCalendar.Visible ) {
        monthCalendar.Visible = false;
      }
    }

    private void OnPropertyChanged( object sender, PropertyChangedEventArgs e ) {
      if ( PropertyChanged != null ) {
        PropertyChanged( sender, e );
      }
    }

    private void textBox_TextChanged( object sender, EventArgs e ) {

      if ( string.IsNullOrEmpty( textBox.Text ) ) {
        this.Value = null;
      }

      try {
        DateTime date = DateTime.Parse( textBox.Text, CultureInfo.CurrentCulture );
        this.Value = date;
        SetTextboxText( );


      } catch ( ArgumentException ) {
        //this.Value = null;
      } catch ( FormatException ) {
        //this.Value = null;
      }
    }

    #endregion

    #region - Private Methods -

    private void DrawButtonLines( Graphics graphics ) {

      if ( monthCalendar.Visible ) {
        SolidBrush brush = new SolidBrush( Color.SteelBlue );
        Pen pen = new Pen( brush );
        GraphicsPath gp = new GraphicsPath( );

        int x, y, w, h;
        x = button.Location.X;
        y = button.Location.Y;
        w = button.Width;
        h = button.Height;

        gp.AddLine( x - 1, y, x - 1, h );             //left line
        gp.AddLine( x + w, 0, x + w, h );             //right line
        gp.AddLine( x - 1, y + h, x + w - 1, y + h ); //bottom line

        graphics.DrawPath( pen, gp );
      }
    }

    private void DrawTopLine( Graphics graphics ) {
      SolidBrush brush = new SolidBrush( Color.SteelBlue );
      brush.Color = monthCalendar.Visible ? Color.SteelBlue : SystemColors.ControlDark;
      Pen pen = new Pen( brush );
      graphics.DrawLine( pen, 0, 0, this.Width - 1, 0 );
    }

    private void SetTextboxText( ) {
      DateTimeFormatInfo dateFormatInfo = CultureInfo.CurrentCulture.DateTimeFormat;
      if ( this.Value.HasValue ) {
        switch ( this.DateFormat ) {
          case DateFormatType.Long:
            textBox.Text = string.Format( CultureInfo.CurrentCulture, "{0:" + dateFormatInfo.LongDatePattern + "}", this.Value.Value );
            break;
          case DateFormatType.Short:
            textBox.Text = string.Format( CultureInfo.CurrentCulture, "{0:" + dateFormatInfo.ShortDatePattern + "}", this.Value.Value );
            break;
          case DateFormatType.Time:
            textBox.Text = string.Format( CultureInfo.CurrentCulture, "{0:" + dateFormatInfo.ShortTimePattern + "}", this.Value.Value );
            break;
          case DateFormatType.Custom:
            textBox.Text = string.Format( CultureInfo.CurrentCulture, "{0:" + customFormat + "}", this.Value.Value );
            break;
          default:
            break;
        }
      }
    }

    #endregion

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
    
  }
}
